﻿using Devil;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;

namespace TableCore
{
    public partial class GTFile
    {
        List<FileFilter> mFilters;
        List<ValueFilter> mValueFilters;
        List<ValueFilter> mCheckNilFilters;
        bool mInitialized;
        string mInitFilter;

        public string FilterFile
        {
            get { return mInitFilter; }
            set
            {
                lock (_lock)
                {
                    if (mInitFilter != value)
                    {
                        mInitFilter = value;
                        mInitialized = false;
                        //InitFilters();
                    }
                }
            }
        }

        void InitFilters()
        {
            if (mInitialized)
                return;
            mInitialized = true;
            if (mFilters == null)
                mFilters = new List<FileFilter>();
            else
                mFilters.Clear();
            if (mValueFilters == null)
                mValueFilters = new List<ValueFilter>();
            else
                mValueFilters.Clear();
            if (mCheckNilFilters == null)
                mCheckNilFilters = new List<ValueFilter>();
            else
                mCheckNilFilters.Clear();
            var regex = new Regex("^(-|/)(include|exclude|check-nil)(-(data|code|col))?( |\t)+", RegexOptions.IgnoreCase);
            var file = mInitFilter;
            if (!string.IsNullOrEmpty(file) && File.Exists(file))
            {
                Debug.LogFormat("filter defination: {0}", file);
                var reader = File.OpenText(file);
                InitFilters(regex, reader);
                reader.Dispose();
                return;
            }

            var envirn = AppDomain.CurrentDomain.BaseDirectory;
            file = Path.Combine(envirn, "Config/TableCore-filter.txt");
            if (File.Exists(file))
            {
                Debug.LogFormat("filter defination: {0}", file);
                var reader = File.OpenText(file);
                InitFilters(regex, reader);
                reader.Dispose();
                return;
            }
            Debug.LogFormat("no filter.");
        }

        void InitFilters(Regex regex, StreamReader reader)
        {
            string str;
            while ((str = reader.ReadLine()) != null)
            {
                str = str.Trim();
                if (!string.IsNullOrEmpty(str))
                {
                    var m = regex.Match(str);
                    if (m != null && m.Success && str.Length > m.Length)
                    {
                        var v = m.Value.ToLower();
                        if (v.Contains("col"))
                        {
                            if (v.Contains("include"))
                                mValueFilters.Add(ValueFilter.Include(str.Substring(m.Length)));
                            else if(v.Contains("exclude"))
                                mValueFilters.Add(ValueFilter.Exclude(str.Substring(m.Length)));
                        }
                        else
                        {
                            int type;
                            if (v.Contains("-code"))
                                type = 1;
                            else if (v.Contains("-data"))
                                type = 2;
                            else
                                type = 0;
                            if (v.Contains("include"))
                                mFilters.Add(FileFilter.Include(str.Substring(m.Length), type == 0 || type == 2, type == 0 || type == 1));
                            else if (v.Contains("exclude"))
                                mFilters.Add(FileFilter.Exclude(str.Substring(m.Length), type == 0 || type == 2, type == 0 || type == 1));
                            else
                                mCheckNilFilters.Add(ValueFilter.Include(str.Substring(m.Length)));
                        }
                    }

                }
            }
        }

        // 文件过滤器
        public class FileFilter
        {
            bool mExclude;
            Regex mPattern;
            bool mForData;
            bool mForCode;

            private FileFilter() { }

            public static bool PassDataFile(string file, IList<FileFilter> filters)
            {
                bool included = false;
                bool hasInclude = false;
                for (int i = 0; i < filters.Count; i++)
                {
                    var f = filters[i];
                    if (f == null || !f.mForData)
                        continue;
                    if (f.mExclude)
                    {
                        if (f.mPattern.IsMatch(file))
                            return false;
                    }
                    else
                    {
                        hasInclude = true;
                        if (f.mPattern.IsMatch(file))
                            included = true;
                    }
                }
                return included || !hasInclude;
            }

            public static bool PassCodeFile(string file, IList<FileFilter> filters)
            {
                bool included = false;
                bool hasInclude = false;
                for (int i = 0; i < filters.Count; i++)
                {
                    var f = filters[i];
                    if (f == null || !f.mForCode)
                        continue;
                    if (f.mExclude)
                    {
                        if (f.mPattern.IsMatch(file))
                            return false;
                    }
                    else
                    {
                        hasInclude = true;
                        if (f.mPattern.IsMatch(file))
                            included = true;
                    }
                }
                return included || !hasInclude;
            }

            public static FileFilter Include(string pattern, bool forData, bool forCode)
            {
                if ((forData || forCode) && !string.IsNullOrEmpty(pattern))
                {
                    var f = new FileFilter();
                    f.mExclude = false;
                    f.mPattern = new Regex(pattern, RegexOptions.IgnoreCase);
                    f.mForData = forData;
                    f.mForCode = forCode;
                    return f;
                }
                else
                {
                    return null;
                }
            }

            public static FileFilter Exclude(string pattern, bool forData, bool forCode)
            {
                if ((forData || forCode) && !string.IsNullOrEmpty(pattern))
                {
                    var f = new FileFilter();
                    f.mExclude = true;
                    f.mPattern = new Regex(pattern, RegexOptions.IgnoreCase);
                    f.mForData = forData;
                    f.mForCode = forCode;
                    return f;
                }
                else
                {
                    return null;
                }
            }
        }

        public class ValueFilter
        {
            bool mExclude;
            Regex mPattern;
            private ValueFilter() { }

            public static ValueFilter Include(string pattern)
            {
                var f = new ValueFilter();
                f.mExclude = false;
                f.mPattern = new Regex(pattern);
                return f;
            }

            public static ValueFilter Exclude(string pattern)
            {
                var f = new ValueFilter();
                f.mExclude = true;
                f.mPattern = new Regex(pattern);
                return f;
            }

            public static bool PassValue(string value, IList<ValueFilter> filters)
            {
                bool included = false;
                bool hasInclude = false;
                for (int i = 0; i < filters.Count; i++)
                {
                    var f = filters[i];
                    if (f == null)
                        continue;
                    if (f.mExclude)
                    {
                        if (f.mPattern.IsMatch(value))
                            return false;
                    }
                    else
                    {
                        hasInclude = true;
                        if (f.mPattern.IsMatch(value))
                            included = true;
                    }
                }
                return included || !hasInclude;
            }
        }
    }
}
